<template>
  <div class="uploader">
    <a-space>
      <a-upload :show-upload-list="false" :accept="accepts.mime" :file-list="fileList" :before-upload="beforeUpload">
        <a-button :disabled="disabled"><a-icon type="upload" />选择文件</a-button>
      </a-upload>
      <a-button type="primary" :loading="uploading" :disabled="finished" @click.stop.prevent="handleUpload">
        开始上传
      </a-button>
    </a-space>
    <upload-preview
      ref="uploadPreviewRef"
      :file-list="fileList"
      :iconSize="iconSize"
      style="margin: 10px 0 0"
      @remove="handleRemove"
    />
  </div>
</template>

<script>
import get from 'lodash-es/get.js';
import isEqual from 'lodash-es/isEqual.js';
import Modal from 'ant-design-vue/es/modal/index.js';
import { FileOutlined } from '@ant-design/icons-vue';
import * as uploadUtils from './uploadUtils.js';
import UploadPreview from './UploadPreview.vue';
import { useUploader } from './useUpload.js';

export default {
  name: 'Uploader',
  components: {
    UploadPreview,
    FileOutlined,
  },
  props: {
    /* 对象数组 [ { uid,url,name,type,suffix,status,... },... ] */
    modelValue: { type: Array, default: undefined },
    /* url 数组或字符串 */
    urls: { type: [String, Array], default: undefined },
    /* name 数组或字符串 */
    names: { type: [String, Array], default: undefined },
    valueType: { type: [String], default: 'string' },
    accept: { type: [String, Array], default: undefined },
    filePath: { type: String, default: '/attachment' },
    maxCount: { type: Number, default: 1 },
    iconSize: { type: String, default: '60px' },
  },
  emits: ['update:modelValue', 'update:urls', 'update:names', 'change'],
  data() {
    return {
      uploading: false,
      finished: false,
      fileList: [],
      fileNames: [],
    };
  },
  computed: {
    disabled() {
      return this.fileList.length >= this.maxCount;
    },
    accepts() {
      return uploadUtils.getAcceptTypes(this.accept, { useDefault: false });
    },
  },
  mounted() {
    this.$watch(
      () => this.urls,
      (values) => {
        values = this.getInputValues(values);
        let urls = this.getResponseData();
        if (!isEqual(urls, values)) {
          let names = this.getInputValues(this.names);
          this.fileList = uploadUtils.getFileList(values, names);
        }
      },
      { immediate: true }
    );
    this.$watch(
      () => this.modelValue,
      (values) => {
        if (Array.isArray(values) && !isEqual(values, this.fileList)) {
          this.fileList = values;
        }
      },
      { immediate: true }
    );
  },
  methods: {
    getInputValues(values) {
      if (typeof values === 'string' && values) {
        values = values.split(',');
      }
      if (Array.isArray(values)) {
        return values;
      }
      return [];
    },
    getResponseData(keyPath) {
      if (!keyPath) {
        keyPath = 'response.data.url';
      }
      return this.fileList.map((item) => get(item, keyPath)).filter(Boolean);
    },
    beforeUpload(file) {
      if (!uploadUtils.isFileAcceptable(file, this.accept)) {
        uploadUtils.handleNotice(this.accept);
        return false;
      }
      file = uploadUtils.getWrappedFile(file, { status: 'waiting' });
      this.fileList = [...this.fileList, file].slice(-1 * Number(this.maxCount));
      return false;
    },
    handleRemove(index) {
      this.fileList.splice(index, 1);
      this.output();
    },
    async handleUpload() {
      const fileList = this.fileList.filter((item) => item.status !== 'done');
      if (!fileList.length) {
        return this.$message.error('没有需要上传的文件,请先选择文件!');
      }
      this.uploading = true;
      const res = await Promise.all(
        fileList.map((file) => {
          const res = useUploader({
            file: file.originFileObj,
            params: (params) => ({ ...params, filePath: this.filePath }),
            onFail: () => (file.status = 'fail'),
            onProgress: (value) => {
              file.progress = value;
            },
            onSuccess: (res) => {
              file.status = 'done';
              file.response = {
                data: { url: res.data.value.url, filename: file.name },
              };
            },
          });
          return res.ready;
        })
      ).catch((e) => {
        return res;
      });
      this.fileList = [...this.fileList];
      this.uploading = false;
      this.output();
      const noError = res.every((item) => !item.error || !item.error.value);
      if (noError) {
        this.$message.success('文件上传成功!');
      }
    },
    async checkUploads() {
      return await new Promise((resolve) => {
        const fileList = this.fileList.filter((item) => item.status !== 'done');
        if (!fileList.length) {
          return resolve();
        }
        Modal.confirm({
          title: '当前有未上传的文件，是否立即上传？',
          onOk: async () => {
            await this.handleUpload();
            resolve();
          },
          onCancel: () => resolve(),
        });
      });
    },
    output() {
      let data = this.getResponseData('response.data');
      let urls = this.getResponseData('response.data.url');
      let names = this.getResponseData('response.data.filename');
      if (this.valueType === 'string') {
        urls = urls.join(',');
        names = names.join(',');
      }
      // console.log(this.fileList);
      // console.log(urls);
      this.$emit('update:urls', urls);
      this.$emit('update:names', names);
      this.$emit('update:modelValue', this.fileList);
      this.$emit('change', data);
    },
  },
};
</script>

<style scoped lang="less"></style>
